package org.spdata.tsdb.server;



import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spdata.tsdb.Application;
import org.spdata.tsdb.client.Query;
import org.spdata.tsdb.dto.DataPoint;
import org.spdata.tsdb.dto.DataPoints;
import org.spdata.tsdb.dto.Response;
import org.spdata.tsdb.service.DataPointService;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.TreeTraversingParser;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class ServerHandler extends ChannelInboundHandlerAdapter{
	private Logger logger = LoggerFactory.getLogger(ServerHandler.class);
	ObjectMapper objMapper = new ObjectMapper();
	
	DataPointService service = null;
	
	public ServerHandler() {
		service = (DataPointService) Application.getBean(DataPointService.class);
	}
	
	
	private Response doPut(JsonNode root,ChannelHandlerContext ctx)throws Exception{		
		Response response = null;
		List<DataPoint> dps = new ArrayList<DataPoint>();
		Iterator<JsonNode> iter = root.iterator();
		while(iter.hasNext()){
			JsonNode node = iter.next();
			DataPoint dp = null;			
			dp = objMapper.readValue(new TreeTraversingParser(node), DataPoint.class);	
			dps.add(dp);
		}
		logger.debug("正在写入{}个采样数据",dps.size());
		service.dealDpList(dps);
		response = Response.success(null);
		return response;
	}
	
	private void doResponse(Response response,ChannelHandlerContext ctx){
		StringBuffer sb = new StringBuffer();
		try {
			sb.append(objMapper.writeValueAsString(response))
				.append("\r\n");
		} catch (JsonProcessingException e) {
			logger.warn("failed to convert Result to Json String!",e);
		}
		String r = sb.toString();		
		ByteBuf encoded = ctx.alloc().buffer(4 * r.length());
		encoded.writeBytes(r.getBytes());
		ctx.write(encoded);
		ctx.flush();
	}
	
	private Response doQuery(JsonNode root,ChannelHandlerContext ctx)throws Exception{
		Response response = null;		
		Query query = (Query) objMapper.readValue(new TreeTraversingParser(root), Query.class);
		List<DataPoints> list = service.query(query);
		response = Response.success(list);
		return response;
	}
	
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object message) throws Exception {
		Response response = null;
		try{
			logger.debug("recieved message from {}:{}",this.getRemoteIp(ctx),message );	
			JsonNode root =objMapper.readTree((String)message);
			String method = root.get("method").asText();
			if(method==null || method.isEmpty()){
				throw new Exception("method is null or empty!");
			}
			if(method.equals("put")){
				response = doPut(root.get("data"),ctx);
			}else if(method.equals("query")){
				response = doQuery(root.get("data"),ctx);
			}
		}catch(Exception e){
			e.printStackTrace();
			logger.error("faile to deal request!",e);
			response = Response.error(e.getMessage());
		}
		this.doResponse(response, ctx);
		
	}
	

	private String getRemoteIp (ChannelHandlerContext ctx){
		InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
		String clientIp = insocket.getAddress().getHostAddress();
		return clientIp;
	}
	

	@Override
	public void channelRegistered(ChannelHandlerContext ctx) throws Exception {		
        logger.info("connected from "+this.getRemoteIp(ctx));
	}



	@Override
	public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {		
        logger.info("disconnected from "+this.getRemoteIp(ctx));
	}



	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		
	}



	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		logger.error("error happened on "+ this.getRemoteIp(ctx) + " :",cause);
        ctx.close();
	}
	
}
